/**
 * A Document's output settings control the form of the text() and html() methods.
 */
import { Validate } from '../helper/Validate';
import { CoreCharset, Entities, EscapeMode } from './Entities';
import { Syntax } from './Syntax';
export class OutputSettings {
  private _escapeMode = EscapeMode.base
  private _charset: string
  coreCharset:CoreCharset; // fast encoders for ascii and utf8
  // private final ThreadLocal<CharsetEncoder> encoderThreadLocal = new ThreadLocal<>(); // initialized by start of OuterHtmlVisitor
  private _prettyPrint = true
  private _outline = false
  private _indentAmount = 1
  private _maxPaddingWidth = 30
  private _syntax = Syntax.html

  constructor() {
    this.setCharset('utf-8')
  }

  /**
   * Get the document's current HTML escape mode: <code>base</code>, which provides a limited set of named HTML
   * entities and escapes other characters as numbered entities for maximum compatibility; or <code>extended</code>,
   * which uses the complete set of HTML named entities.
   * <p>
   * The default escape mode is <code>base</code>.
   * @return the document's current escape mode
   */
  public getEscapeMode(): EscapeMode {
    return this._escapeMode
  }

  /**
   * Set the document's escape mode, which determines how characters are escaped when the output character set
   * does not support a given character:- using either a named or a numbered escape.
   * @param escapeMode the new escape mode to use
   * @return the document's output settings, for chaining
   */
  public setEscapeMode(escapeMode: EscapeMode): OutputSettings {
    this._escapeMode = escapeMode
    return this
  }

  /**
   * Get the document's current output charset, which is used to control which characters are escaped when
   * generating HTML (via the <code>html()</code> methods), and which are kept intact.
   * <p>
   * Where possible (when parsing from a URL or File), the document's output charset is automatically set to the
   * input charset. Otherwise, it defaults to UTF-8.
   * @return the document's current charset.
   */
  public getCharset(): string {
    return this._charset
  }

  /**
   * Update the document's output charset.
   * @param charset the new charset to use.
   * @return the document's output settings, for chaining
   */
  public setCharset(charset: string): OutputSettings {
    this._charset = charset
    this.coreCharset = Entities.byName(charset)
    return this
  }

  /**
   * CharsetEncoder prepareEncoder() {
   // created at start of OuterHtmlVisitor so each pass has own encoder, so OutputSettings can be shared among threads
   CharsetEncoder encoder = charset.newEncoder();
   encoderThreadLocal.set(encoder);
   return encoder;
   }

   CharsetEncoder encoder() {
   CharsetEncoder encoder = encoderThreadLocal.get();
   return encoder != null ? encoder : prepareEncoder();
   }
   */

  /**
   * Get the document's current output syntax.
   * @return current syntax
   */
  public getSyntax(): Syntax {
    return this._syntax
  }

  /**
   * Set the document's output syntax. Either {@code html}, with empty tags and boolean attributes (etc), or
   * {@code xml}, with self-closing tags.
   * @param syntax serialization syntax
   * @return the document's output settings, for chaining
   */
  public setSyntax(syntax: Syntax): OutputSettings {
    this._syntax = syntax
    return this
  }

  /**
   * Get if pretty printing is enabled. Default is true. If disabled, the HTML output methods will not re-format
   * the output, and the output will generally look like the input.
   * @return if pretty printing is enabled.
   */
  public getPrettyPrint(): boolean {
    return this._prettyPrint;
  }

  /**
   * Enable or disable pretty printing.
   * @param pretty new pretty print setting
   * @return this, for chaining
   */
  public prettyPrint(pretty: boolean): OutputSettings {
    this._prettyPrint = pretty;
    return this;
  }

  /**
   * Get if outline mode is enabled. Default is false. If enabled, the HTML output methods will consider
   * all tags as block.
   * @return if outline mode is enabled.
   */
  public getOutline():boolean {
    return this._outline
  }

  /**
   * Enable or disable HTML outline mode.
   * @param outlineMode new outline setting
   * @return this, for chaining
   */
  public setOutline(outlineMode:boolean) :OutputSettings {
    this._outline = outlineMode
    return this
  }
  /**
   * Get the current tag indent amount, used when pretty printing.
   * @return the current indent amount
   */
  public getIndentAmount(): number {
    return this._indentAmount
  }

  /**
   * Set the indent amount for pretty printing
   * @param indentAmount number of spaces to use for indenting each level. Must be {@literal >=} 0.
   * @return this, for chaining
   */
  public setIndentAmount(indentAmount:number) :OutputSettings {
    Validate.isTrue(indentAmount >= 0)
    this._indentAmount = indentAmount
    return this
  }

  /**
   * Get the current max padding amount, used when pretty printing
   * so very deeply nested nodes don't get insane padding amounts.
   * @return the current indent amount
   */
  public getMaxPaddingWidth():number {
    return this._maxPaddingWidth
  }

  /**
   * Set the max padding amount for pretty printing so very deeply nested nodes don't get insane padding amounts.
   * @param maxPaddingWidth number of spaces to use for indenting each level of nested nodes. Must be {@literal >=} -1.
   *        Default is 30 and -1 means unlimited.
   * @return this, for chaining
   */
  public setMaxPaddingWidth(maxPaddingWidth:number):OutputSettings {
    Validate.isTrue(maxPaddingWidth >= -1)
    this._maxPaddingWidth = maxPaddingWidth
    return this
  }

  public clone():OutputSettings {
    let clone: OutputSettings = new OutputSettings()
    try {
      clone = Object.assign(clone, this)
    } catch (e) {

    }
    clone.setCharset(this._charset)
    clone._escapeMode = this._escapeMode
    // indentAmount, maxPaddingWidth, and prettyPrint are primitives so object.clone() will handle
    return clone;
  }
}
